#include "evpath.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <bitset>
#include <map>
#include <string>
#include <iostream>
#include <queue>
#include "util.h"
#include <sstream>
#include <algorithm>
#include <vector>
#include <math.h>
#include <locale>
using namespace std;

int global_count = 0;
int global_max = 0;

template <class T>
bool from_string(T& t,
                 const string& s,
                 ios_base& (*f)(ios_base&))
{
  istringstream iss(s);
  return !(iss >> f >> t).fail();
}

void Tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}


string exec(string cmd) {
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) return "PIPE File ERROR";
    char buffer[128];
    string result = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
                result += buffer;
    }
    pclose(pipe);
    return result;
}

/*collect the average overall CPU utilization of a local host for the past x second*/
float collectCPU(int period) {
  vector<string> tokens;
  string result = exec("sar -u 1 1 | tail -n 1");
  Tokenize(result, tokens);
  float cpu;
  if(from_string<float>(cpu, tokens[7], dec)) {
    return cpu;
  }
  else {
    cout << "string conversion failed" << endl;
    return -1;
  }
}

/*collect the average overall Memory utilization of a local host for the past x second*/
float collectMEM(int period) {
  vector<string> tokens;
  string result = exec("sar -r 1 1 | tail -n 1");
  Tokenize(result, tokens);
  float mem;
  if(from_string<float>(mem, tokens[3], dec)) {
    return mem;
  }
  else {
    cout << "string conversion failed" << endl;
    return -1;
  }
}

float collectREQ(int period) {
  struct stat stFileInfo;
  if(stat("/root/rubis/apache-install/logs/mod_jk.log",&stFileInfo)) return 0.0;
  string result = exec("tail /root/rubis/apache-install/logs/mod_jk.log -n 1");
  //cout << result << endl;
  vector<string> tokens;
  float req;
  Tokenize(result, tokens);
  if((int)tokens.size() != 9) return 0.0;
  if(from_string<float>(req, tokens[8], dec)) {
    return req;
  }
  else {
    cout << "string conversion failed" << endl;
    return -1;
  }
}

int collectCPUMEM(int period, float* cpu, float* mem) {
  string result = exec("sar -ur 1 1 | tail -n 5");
  vector<string> tokens;
  Tokenize(result, tokens);
  if(from_string<float>(*cpu, tokens[14], dec) && from_string<float>(*mem, tokens[24], dec)) {
    *cpu = 100.0 - *cpu;
    return 0;
  }
  else {
    cout << "string conversion failed" << endl;
    return -1;
  }
}

int max (int *array) {
  int max = array[0];
  int length = sizeof(array)/sizeof(int);
  for(int i = 1; i < length; i++) {
    if(array[i] > max) max = array[i];
  }
  return max;
}

float localEntropy(queue<simple_rec> LBW, int BIN_NUMBER, int RANGE) {

  int bins[BIN_NUMBER];
  float cpus[LBW_LENGTH];
  
  float mean = 0.0;   
  float entropy = 0.0;   
  float norm = 0.0;
  int i; 
  // calculate mean value of samples in buffer
  for(i = 0; i < LBW_LENGTH; i ++) {
    cpus[i] = LBW.front().cpu;
    mean += cpus[i];
    LBW.push(LBW.front());
    LBW.pop();
  }
  mean /= LBW_LENGTH;
  
  if(mean == 0) return 0.0; //mean is zero means every cpu value is 0 
  // setup counters
  for(i = 0; i < BIN_NUMBER; i ++) {
    bins[i] = 0;
  }     
 
  for(i = 0; i < LBW_LENGTH; i ++) {
    norm = cpus[i] / mean;
    int bin_index = (int) floor(norm * (BIN_NUMBER-1) / RANGE);   
    if(bin_index >= BIN_NUMBER - 1) {
      bin_index = BIN_NUMBER - 1;
    }
    bins[bin_index] ++; 
  }   
  
  for(i = 0; i < BIN_NUMBER; i ++) {
    float p = (float)bins[i] / LBW_LENGTH;
    if(p != 0) { 
      entropy = -1 * p * log(p) + entropy; 
    }
  } 
  
  return entropy;
}

long getFlumeLatency(string s) {
  struct timeval start, end;
  string writecmd = "echo \"1616:";
  writecmd.append(s);
  writecmd.append("\" >> /root/flume/cheng/testlogs/test.hb");
  int i = system(writecmd.c_str());
  gettimeofday(&start, NULL);
  string javacmd = "java -cp /root/monalytics/test/helloworlds/middleware/bin:/root/hbase_lib/conf:/root/hbase_lib/lib/* hbaseclient.client ";
  javacmd.append(s);
  int count = 0; 
  while(exec(javacmd).compare("") == 0) {
    usleep(500000);
    if(count == 10) {
      gettimeofday(&end, NULL);
      long delay = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
      return delay;
    }  
    count++;
  }
  gettimeofday(&end, NULL);
  long latency = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
  return latency;
}

//int get_index(char* ids[], char* id, int num_ids){
//  for(int i = 0; i < num_ids; i++) {
 //   if(strcmp(ids[i], id) == 0) return i;
//  }
//  return -1;
//}

string get_flume_debug(char* host_name, int restarted) {
  if(restarted == 0) {
    cout << "turn on " << exec("cp -r /root/flume/cheng/flume/slf4j-*.jar /root/flume/cheng/flume/lib/") << endl; 
    cout << "stop " << exec("pkill -f agent") << endl;
    sleep(2);
    cout << "start " << exec("/root/flume/cheng/flume/bin/flume-daemon.sh start node") << endl;
   }
  char cmd[100];
  sprintf(cmd, "tail -1 /root/flume/cheng/flume/logs/flume-root-node-%s.log", host_name);
  return exec(cmd);
}

string get_hbase_debug(char* host_name) {
  char cmd[100];
  sprintf(cmd, "tail -1 /root/flume/cheng/flume/logs/hbase-root-regionserver-%s.log", host_name);
  return exec(cmd);
}

int checkDup(double* cArray, int end, long a) {
  for(int i = 0 ; i <= end; i++)
    if(cArray[i] == a) return 1;
  return -1;
}

int collectConnection(double cArray[]) {
  vector<string> tokens;
  string result = exec("netstat -t");
  Tokenize(result, tokens, "\n");
  
  //cout << "size " << tokens.size() << endl;
  int size = tokens.size();
  //for(int i = 0; i < size; i++) {
    //cout << tokens[i] << endl;
  //}
  locale loc;
  const collate<char>& coll = use_facet<collate<char> >(loc);
  
  int curIndex = 0; 
  for(int i = 2; i < size; i++) { 
    vector<string> tokens1;
    Tokenize(tokens[i], tokens1, " .");
    //cout << tokens1[6] << endl;
    long hash = coll.hash(tokens1[6].data(), tokens1[6].data() + tokens1[6].length());
    if(i == 2) { 
      cArray[0] = hash*1.0;
      //cout << " first "<<curIndex<<" "<<tokens1[6] <<" "<< hash << endl;
   } 
    else {
      //cout <<"before checkDup " << hash << endl;
      if(checkDup(cArray, curIndex, hash) == -1) {
        curIndex++;
        cArray[curIndex] = hash*1.0;
        //cout << " "<<curIndex<<" "<<tokens1[6] <<" "<< hash << endl;
      }
    }
  }
  //cout << "done" << endl;
  return curIndex;
}

int simple_handler(CManager cm, void *vevent, void *client_data, attr_list attrs)
{
  simple_rec_ptr event = (simple_rec_ptr)vevent;
  //exit(-1);
  //printf("%d \n", event->integer_field);
  
  //if(event->integer_field > global_max) {
  //  global_max = event->integer_field;
  //}
  //if(global_count == 100) {
  //  printf("%d\n", global_max);
  //  global_count = 0;
  //} else {
  //  global_count ++;
  //}
  //for(int i = 0; i < 20; i++) {
    //printf("%ld ", event->cArray[i]);
  //}
  //printf("\n");
}
